//! minigrep
//! 这是一个单元包概述
//! minigrep 是一个命令行程序，它允许用户搜索文本文件内容。

/// 参数配置结构体
#[derive(Debug)]
pub struct Config {
    /// 被搜索的文件名，可以是全路径（含文件名），也可以不含路径的文件名
    pub file_name: String,
    /// 从被搜索的文件中查找的字符串
    pub target: String,
    /// 是否显示帮助信息.仅当用户输入的第一个参数为 --help 时，该值为 true
    pub show_help: bool,
}

/**
 * 处理参数的模块 <br>
 * 包括 build、is_too_big,show_help
 */
pub mod config {
    use super::Config;
    use std::env;
    use std::fs;
    use std::path::Path;

    /// **构建一个参数配置结构体** <br>
    /// **args** 参数列表 ,数组类型，非空。第一个表示程序路径，第二个为target_name,第三个为file_path <br>
    /// 返回： 参数配置结构体<br>
    /// 异常:   如果参数异常则返回错误信息<br>
    /// 例子：
    /// ```
    /// use std::env;
    /// use minigrep::{config,search};
    /// fn main() {
    ///   let args: Vec<String> = env::args().collect();
    ///   let con=config::build(&args).unwrap_or_else(|err|{
    ///       eprintln!("程序异常:{}",err);
    ///       std::process::exit(1);
    ///     });
    /// }
    /// ```
    pub fn build(args: &[String]) -> Result<Config, &str> {
        if args.len() < 3 {
            if args.len() == 2 {
                //如果target_name=="--help"则打印帮助信息,否则执行文件
                let target_name = args[1].clone();
                if target_name == "--help" {
                    return Ok(Config {
                        target: target_name,
                        file_name: "".to_string(),
                        show_help: true,
                    });
                }
            }
            return Err("必须有两个参数");
        }
        println!("rust返回的程序路径:{}", args[0]);
        let target_name = args[1].clone();
        let file_path = args[2].clone();

        if !file_exists(&file_path) {
            //用户输入的是文件名
            let exec_path = get_current_exec_path();
            println!("当前执行路径：{}", exec_path);
            let mut tmp_path = exec_path.clone() + &file_path;
            if !file_exists(&tmp_path) {
                tmp_path = exec_path.clone().replace("\\target\\debug\\", "\\src\\") + &file_path;
                if !file_exists(&tmp_path) {
                    tmp_path =
                        exec_path.clone().replace("\\target\\release\\", "\\src\\") + &file_path;
                    if !file_exists(&tmp_path) {
                        return Err("文件不存在");
                    }
                }
                //在src下
                Ok(Config {
                    target: target_name,
                    file_name: tmp_path,
                    show_help: false,
                })
            } else {
                //在当前目录下=执行路径+文件名
                Ok(Config {
                    target: target_name,
                    file_name: tmp_path,
                    show_help: false,
                })
            }
        } else {
            //在当前目录下 -- 即用户输入的是全路径
            println!("{}", file_path);
            Ok(Config {
                target: target_name,
                file_name: file_path,
                show_help: false,
            })
        }
    }

    /**
     * 判断文件是否存在，如果存在则返回true,否则返回false
     */
    fn file_exists(file_name: &String) -> bool {
        Path::new(&file_name).exists()
    }

    /**
     * 获取当前执行路径，最后会包含分隔符号\
     * 例如 d:\soft\rust-test\
     * 注意：仅限用于windows平台
     */
    fn get_current_exec_path() -> String {
        let cur_dir = match env::current_exe() {
            Ok(exe_path) => exe_path.display().to_string(),
            Err(e) => panic!("获取当前路径失败:{}", e),
        };
        // 获取cur_dir的目录，不需要包含文件名称
        let path = Path::new(&cur_dir);
        let result = path.parent().unwrap().to_str().unwrap().to_string() + "\\";
        result
    }

    /// 判断文件是否超过1Mb,如果超过则返回true,否则返回false
    pub fn is_too_big(file_name: &String) -> bool {
        //判断file_name是否超过1Mb,如果是，则返回true,否则返回false
        let file_size = fs::metadata(file_name).unwrap().len();
        if file_size > 1 * 1024 * 1024 {
            return true;
        } else {
            false
        }
    }

    /// 打印帮助信息
    pub fn show_help() {
        println!("用法:minigrep target path");
        println!("     minigrep --help");
        println!("参数:");
        println!("  target  需要查找的目标字符串");
        println!("  path    包含target的文件，可以是全路径，也可以是文件名");
        println!("          如果是文件名，则会尝试在当前目录下，或者是在相对路径..\\..\\src");
        println!("  --help  查看帮助");
        println!("示例:");
        println!("  minigrep 宋 E:\\learning\\gitee\\rust-org\\test-1\\minigrep\\src\\古诗.txt ");
        println!("  minigrep 宋 古诗.txt");
        println!("版本 1.0 for windows, 作者->lzfto");
    }
}

/**
 * 模块执行搜索
 */
pub mod search {
    use super::Config;
    use std::fs;
    use std::fs::File;
    use std::io::{BufRead, BufReader};
    use std::path::Path;
    /**
     * 搜索小于1M的文件，并返回查找的结果
     */
    pub fn search_small_file(con: &Config) -> Vec<String> {
        let contents = fs::read_to_string(con.file_name.clone()).expect("文件不存在");
        println!("文章内容:\n{}", contents);
        //把contents根据换行符切割成向量
        let mut result: Vec<String> = vec![];
        let lines = contents.lines();
        for line in lines {
            if line.find(&con.target).is_some() {
                result.push(line.to_string());
            }
        }
        return result;
    }
    /**
     * 搜索大于1M的文件,并在搜索过程中直接打印结果<br>
     * 返回表示成功与否的信息 Result<()>
     */
    pub fn searh_big_file(file_name: &String, target: &String) -> std::io::Result<()> {
        //打开文件file_name,逐行查找,找到则直接打印
        let path = Path::new(file_name);
        let file = File::open(&path)?;
        let reader = BufReader::new(file);
        for line in reader.lines() {
            match line {
                Ok(line) => {
                    if line.find(target).is_some() {
                        println!("{}", line);
                    }
                }
                Err(e) => println!("Error reading line: {}", e),
            }
        }
        Ok(())
    }
}
